package com.ht.WeNas.service;

import cn.hutool.core.io.IORuntimeException;
import com.ht.WeNas.data.dto.FileObj;
import com.ht.WeNas.data.vo.ResPage;
import com.ht.WeNas.utils.MyPathUtil;
import com.ht.WeNas.utils.MyThreadPool;
import com.ht.WeNas.utils.exceptions.MessageException;
import org.springframework.stereotype.Service;
import org.yaml.snakeyaml.util.UriEncoder;
import ws.schild.jave.EncoderException;
import ws.schild.jave.MultimediaObject;
import ws.schild.jave.info.MultimediaInfo;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;

@Service
public class FileService {
    public List<FileObj> getHomeDir() {
        List<FileObj> res = new ArrayList<>();
        FileSystems.getDefault().getRootDirectories()
                .forEach(item -> {
                    res.add(FileObj.getInstance(item));
                });
        return res.stream().sorted(FileObj.getComparator(new String[]{"type", "name"})).toList();
    }

    public ResPage<FileObj> pageDirByPath(String path, int pageCurrent, int pageSize) {
        Path targetDir = Path.of(path);
        if (Files.isDirectory(targetDir) && Files.isReadable(targetDir)) {
            try (Stream<Path> list = Files.list(targetDir)) {
                List<Path> pathList = list.sorted(MyPathUtil.getNaturalComparator()).toList();
                ResPage<Path> page = ResPage.fromList(pageCurrent, pageSize, pathList);
                if (page.getRecords().isEmpty()) {
                    return new ResPage<>(pageCurrent, pageSize, 0, List.of());
                }
                return ResPage.mapList(page, records ->
                        records.stream()
                                .map(p -> MyThreadPool.execAsync(() -> FileObj.getInstance(p)))
                                .map(future -> {
                                    try {
                                        return future.get();
                                    } catch (InterruptedException | ExecutionException e) {
                                        return null;
                                    }
                                })
                                .filter(Objects::nonNull)
                                .sorted(FileObj.getComparator(new String[]{"type"}))
                                .toList()
                );
            } catch (IOException e) {
                throw new MessageException("文件读取失败，请检查参数");
            }
        } else {
            throw new MessageException("拒绝访问");
        }
    }

    /**W
     * 获取文件的m3u8文件
     * @param fileObj ts媒体文件
     */
    public String getM3U8String(FileObj fileObj) {
        String type = fileObj.getType();
        if (!"ts".equals(type) || fileObj.isDir()) {
            throw new MessageException("请求了错误的文件");
        }

        MultimediaObject multimediaObject = new MultimediaObject(new File(fileObj.getPath()));
        try{
            MultimediaInfo info = multimediaObject.getInfo();
            long duration = info.getDuration();
            long sharding = duration / 10000;
            long size = fileObj.getSize();
            long partSize = size / sharding;
            StringBuilder builder = new StringBuilder();
            builder.append("#EXTM3U\n");
            builder.append("#EXT-X-VERSION:3\n");
            builder.append("#EXT-X-TARGETDURATION:").append(duration / 1000).append("\n");
            builder.append("#EXT-X-MEDIA-SEQUENCE:0\n");
            builder.append("#EXT-X-PLAYLIST-TYPE:VOD\n");
            for (int i = 0; i < sharding; i++) {
                builder.append("#EXTINF:10.0,\n");
                builder.append("/api/file/m3u8/stream?start=")
                        .append(i * partSize)
                        .append("&length=")
                        .append(partSize)
                        .append("&path=")
                        .append(UriEncoder.encode(fileObj.getPath()))
                        .append("\n")
                ;
            }
            builder.append("#EXT-X-ENDLIST");
            return builder.toString();
        } catch (EncoderException e) {
            throw new MessageException("文件读取失败，不支持的类型");
        }
    }

    /**
     * 通过链接读取 ts 媒体文件通过流输出
     * @param path ts文件链接
     * @param start 起始位置（byte）
     * @param length 读取长度（byte）
     * @param os 输出流
     */
    public void streamM3U8(String path, long start, long length, OutputStream os) {
        try (RandomAccessFile fileReader = new RandomAccessFile(path, "r")) {
            fileReader.seek(start);
            byte[] cache = new byte[8 * 1024];
            int n;
            while ((n = fileReader.read(cache)) != -1) {
                if (length < n) {
                    os.write(cache, 0, (int) length);
                    os.flush();
                    break;
                } else {
                    length -= n;
                    os.write(cache, 0, n);
                    os.flush();
                }
            }
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }
}
